package com.aspirecn.core.datacache;

import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.Range;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;

import com.aspirecn.core.commons.Configuration;
import com.aspirecn.core.commons.IPUtils;
import com.aspirecn.core.object.IP;
import com.aspirecn.core.object.IPRange;
import com.csvreader.CsvReader;

/**
 * IP段缓存
 * 
 * @author wangxinning
 * 
 */
public class IPRangeCache extends BaseLocalCache {

	public final static Logger logger = Logger.getLogger(IPRangeCache.class);

	private static IPRangeCache instance = new IPRangeCache();
	
	private GEOCache geoCache = GEOCache.getInstance();
	private IPGatewayCache ipGatewayCache = IPGatewayCache.getInstance();
	private List<IPRange> ipRangeList = new ArrayList<IPRange>();
	private Map<Integer,Integer> ipStartPosition = new HashMap<Integer,Integer>();
	public final static int IPRANGE = 100000;//间隔，经验证这个数字最合适

	public int getCount()
	{
		return ipRangeList.size();
	}
	
	private IPRangeCache() {
		this.dataFile = new File(Configuration.getInstance()
				.getDownloadFilePath() + File.separator + "ip.csv");
		load();
	}

	public static IPRangeCache getInstance() {
		return instance;
	}

	@Override
	public void load() {

		if (!loading.getAndSet(true) && Configuration.getInstance().switchIPCache() && this.dataFile.exists()) {

			long start = System.currentTimeMillis();

			if (ipRangeList.isEmpty() && this.dataFile.exists()) {
				try {
					CsvReader reader = new CsvReader(this.dataFile.toString(),
							',', Charset.forName("gbk"));

					while (reader.readRecord()) {
						IPRange ipRange = new IPRange();
						
						ipRange.setStartIpNum(NumberUtils.toLong(reader.get(0)));
						ipRange.setEndIpNum(NumberUtils.toLong(reader.get(1)));

						int cityid = NumberUtils.toInt(reader.get(9));
						int provinceid = NumberUtils.toInt(reader.get(7));

						ipRange.setCity(geoCache.getCity(cityid));
						ipRange.setProvince(geoCache.getProvince(provinceid));

						this.ipRangeList.add(ipRange);
					}
					
					reader.close();
					
				} catch (Exception e) {

					loading.set(false);
					logger.error("ip段数据加载失败", e);
					return;
				}
			}

			loading.set(false);
			long end = System.currentTimeMillis();
			updateFileDownloadTime();
			
			//按照startnum的顺序从小到大排列
			Collections.sort(ipRangeList);
			
			//将数据分段，记录每段起始位置。范围一亿
			for( int i = 0; i < ipRangeList.size(); i++ )//记录位置
			{
				IPRange range = ipRangeList.get(i);
								
				//System.out.println( range.getStartIpNum() );
				long po = range.getStartIpNum()/IPRANGE;

				if( ipStartPosition.get((int)po ) == null )
				{
					ipStartPosition.put((int)po,i);
				}
			}
			
			logger.info("IP段信息加载完成，time=" + (end - start) + "ms,size="
					+ this.ipRangeList.size());
		} else {
			logger.info("配置关闭，IP段信息未加载");
		}
		
		
		loading.set(false);
	}

	@Override
	public void clear() {

		ipRangeList.clear();
		ipStartPosition.clear();
	}

	@Override
	public void reload() {

		if (this.fileIsChange()) {
			this.clear();
			this.load();
		} else {
			logger.info("没变化，IP段信息未加载");
		}
	}

	private IP search(long longIP) {

		if (this.isLoading()) {
			return null;
		}

		//不在数据范围，返回空
		long startip = ipRangeList.get(0).getStartIpNum();
		long endip = ipRangeList.get(ipRangeList.size()-1).getEndIpNum();
		if( longIP < startip || longIP > endip )
		{
			return null;
		}
		
		String ipStr = IPUtils.longToIP(longIP);
		
		long start = System.currentTimeMillis();
		IP ip = null;
		
		int logtimes = 0;
		//计算开始位置结束位置
		long po = longIP/IPRANGE;
		int startno = 0;
		int endno = ipRangeList.size()-1;
		//读取开始标记
		if( ipStartPosition.get((int)po ) != null )
		{
			startno = ipStartPosition.get((int)po );
		}
		//读取结束标记
		if( ipStartPosition.get((int)po + 1 ) != null )
		{
			endno = ipStartPosition.get((int)po + 1 );
		}
		
		//减少比较次数
		for (int i = startno; i < endno; i++) {
			IPRange tempIPRange = ipRangeList.get(i);
			logtimes++;
			if (longIP >= tempIPRange.getStartIpNum()
					&& longIP <= tempIPRange.getEndIpNum()) {
				ip = new IP();
				ip.setIpAddress(ipStr);
				ip.setCity(tempIPRange.getCity());
				ip.setProvince(tempIPRange.getProvince());
				IP gatewapIP = ipGatewayCache.search(ipStr);
				if (gatewapIP != null) {
					ip.setGateway(gatewapIP.getGateway());
				}
				break;
			}
		}
		
		//没有地区信息，确认其网关信息，避免地区IP数据错误的情况发生
		if( ip == null )
		{
			ip = ipGatewayCache.search(ipStr);
		}

		long end = System.currentTimeMillis();
		logger.debug("搜索IP段，比较次数：" + logtimes + ";logtimes=" + (end - start)
				+ "ms!ip＝" + ipStr);
		return ip;
	}

	public IP search(String ip) {

		long ipLong = IPUtils.ipToLong(ip);
		return search(ipLong);
	}

	public static void main(String[] args) {
		IPRangeCache ipRangeCache = IPRangeCache.getInstance();
		System.out.println(ipRangeCache.search("1.1.1.1"));
		// System.out.println( IPUtils.longToIP(3670951181L) );
	}
}
